package dice.sinanya.tools.makedata;

import com.forte.qqrobot.beans.messages.types.MsgGetTypes;
import dice.sinanya.entity.EntityTypeMessages;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Random;

import static dice.sinanya.system.MessagesBanList.groupSwitchHashMap;
import static dice.sinanya.tools.makedata.Sender.sender;
import static java.lang.Math.ceil;
import static java.lang.Math.max;

/**
 * @author SitaNya
 * 日期: 2019-06-15
 * 电子邮箱: sitanya@qq.com
 * 维护群(QQ): 162279609
 * 有任何问题欢迎咨询
 * 类说明: 最重要的随机数生成类，骰娘的所有随机数都取决于这里
 * <p>
 * 这里为了效果，没有使用单纯的随机数，而是微正态分布
 * <p>
 * 也就是说，不是以绝对公平的随机为准
 * 而是以千次骰点成功率符合跑团预期为准
 */
public class RandomInt {
    private static final Logger log = LogManager.getLogger(RandomInt.class.getName());
    private static final Random r = new Random();

    private RandomInt() {
        throw new IllegalStateException("Utility class");
    }

    public static int random(int lowest, int highest) {
        return randomMersenne(lowest, highest);
    }

    public static int random(int lowest, int highest, EntityTypeMessages entityTypeMessages) {
        long groupId = 0;
        if (!entityTypeMessages.getMsgGetTypes().equals(MsgGetTypes.privateMsg)) {
            groupId = entityTypeMessages.getFromGroup();
        }
        if (groupSwitchHashMap.containsKey(groupId)) {
            switch (groupSwitchHashMap.get(groupId).getAlgorithmTypes()) {
                case Default:
                    return randomDefault(lowest, highest);
                case Expect:
                    return randomExpect(lowest, highest);
                case Bear:
                    if (random(0, 100) == 100) {
                        sender(entityTypeMessages, "由熊哥特别算法得出:\n");
                    }
                    return bearRan(lowest, highest);
                default:
                    return randomMersenne(lowest, highest);
            }
        } else {
            return randomMersenne(lowest, highest);
        }
    }

    /**
     * 尝试了系统随机数和梅森旋转
     * 梅森旋转就他娘的是个憨憨！
     * 当然也可能是我没调好
     * 但最终系统随机数+高斯分布的均值+2方差结果较为满意
     * <p>
     * rc的千次骰掷大成功/大失败概率稳定在0.8%-1.2%左右
     * ra的千次骰掷大成功/大失败概率稳定在4-6%左右
     * <p>
     * 由于需要用到均值，采用最高减最低向上取整并最低为1的计算方式
     *
     * @param lowest  最低值
     * @param highest 最高值
     * @return 随机数结果
     */
    public static int randomExpect(int lowest, int highest) {
        int result;
        int times = 0;
        do {
            int mean = max((int) ceil((highest - lowest) / 2.0), 1);
            result = (int) ((mean + 2) * r.nextGaussian() + mean);
            times++;
        } while ((result > highest || result < lowest) && times < 50);
        if (times >= 50) {
            log.info("使用原始骰点逻辑");
            result = overRandom(lowest, highest);
        }
        return result;
    }

    static int overRandom(int lowest, int highest) {
        int result = 0;
        while (result == 0) {
            result = r.nextInt(highest + 1 - lowest) + lowest;
        }
        return result;
    }

    public static int randomDefault(int lowest, int highest) {
        Random random = new Random();
        return random.nextInt(highest - lowest + 1) + lowest;
    }

    public static int randomMersenne(int lowest, int highest) {
        MersenneTwister mersenneTwister = new MersenneTwister(randomDefault(0, 1000));
        return mersenneTwister.nextInt(highest - lowest + 1) + lowest;
    }


    /**
     * 给朋友做的算法，绝对不是公平的，不过也限定了只有他一个人可以开启这个算法，开启时会全群广播
     *
     * @param lowest  最低值
     * @param highest 最高值
     * @return 结果
     */
    public static int bearRan(int lowest, int highest) {
        int result;
        int times = 0;
        do {
            int mean = 20;
            result = (int) (mean * r.nextGaussian());
            times++;
        } while ((result > highest || result < lowest) && times < 5);
        if (times >= 5) {
            log.debug("使用原始骰点逻辑");
            result = overRandom(lowest, highest);
        }
        return result;
    }
}
